Skip to contents

tmap.mapgl also features a new layer type, tm_polygons_3d, which is only available for the "mapbox" and "maplibre" modes.

This map layer is the same as tm_polygons, with one addition: polygons can be extruded into 3D shapes. The visual variable to control this is called height.

Example: buildings heights

tmap_mode("maplibre")
#>  tmap mode set to "maplibre".

# get vector buildings
library(osmdata)
#> Data (c) OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright
buildings <- opq(bbox = "Marina Bay, Singapore") |>
    add_osm_feature(key = "building") |>
    osmdata_sf()

# prepare levels column, assuming 2 if NA
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> 
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> 
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
buildings_poly <- buildings$osm_polygons |>
    mutate(levels = as.numeric(`building:levels`),
           .before = 1) |>
    mutate(levels = if_else(is.na(levels), 2, levels),
           height = levels * 3.5) # rough height estimate in meters

For the time being, we need to compute the maximum building height, because tm_scale_asis doesn’t support units yet.

# maximum building height
mx = max(buildings_poly$height)

# plot
tm_shape(buildings_poly) +
    tm_polygons_3d(height = "height", options = opt_tm_polygons_3d(height.max = mx)) + 
    tm_maplibre(pitch = 60)
#> No legends available in mode "maplibre" for map variables
#> "height"

Example: population density data

NLD_dist$pop_dens = NLD_dist$population / NLD_dist$area

tm_shape(NLD_dist) +
  tm_polygons_3d(height = "pop_dens",
    fill = "edu_appl_sci",
    fill.scale = tm_scale_intervals(style = "kmeans", values = "-pu_gn"),
    fill.legend = tm_legend("University degree")) +
tm_maplibre(pitch = 45)
#> No legends available in mode "maplibre" for map variables
#> "height"